#include "../include/builtinFunctions.h"
//#include "../include/minishellBase.h"

// length of the builtin-function list
size_t fcnList_len = 2;

// load the builtin function list
void load_fcnList(PROMPT_TYPE *selfDef_types){
	/**
	 * @brief Loads and initializes the function list with predefined properties.
	 *
	 * This function allocates memory for the function list and sets the properties 
	 * (such as command length, maximum parameter number, command text, parameter 
	 * delimiters, and function pointer) of the first function in the list, which is 
	 * the "print" function in this case.
	 *
	 * @param selfDef_types Pointer to the function list to be initialized.
	 */
	

	// echo
	selfDef_types[0].cmd_length = 4; selfDef_types[0].max_para_num = 1;
	selfDef_types[0].cmd_text = (char *) calloc(selfDef_types[0].cmd_length+1, sizeof(char));
	strcpy(selfDef_types[0].cmd_text, "echo");

	selfDef_types[0].fcn_ptr = &_ECHO;

	// cd
	selfDef_types[1].cmd_length = 2; selfDef_types[1].max_para_num = 1;
	selfDef_types[1].cmd_text = (char *) calloc(selfDef_types[1].cmd_length+1, sizeof(char));
	strcpy(selfDef_types[1].cmd_text, "cd");
	
	selfDef_types[1].fcn_ptr = &_CD;
}


// === built-in commands ===
PARSER * _ECHO(PARSER * cmd){ // echo
	/**
		* @brief	Simulate the behavior of command "echo"
		* 
		* @param	cmd pointer to the PARSER structure
		*
		* @return	cmd pointer to the PARSER structure
		*/
	char *token_buffer = (char *) calloc(MAX_PROMPT_LENGTH,sizeof(char));
	char *string_buffer = cmd->cmd_string;
	char * envValue = NULL; // environmental variable value  ; (char*) calloc(ENV_VALUE_LENGTH,sizeof(char))
	char * notUppercase_signal = NULL; // signal the non-uppercase char occurrs after '$', which is set to be the first non-uppercase char if exists or to be NULL_CHAR if no non-uppercase char occurs.

	// allocate the memory space of the parameters of the "echo"
	cmd->parameters = (char **) calloc(cmd->selfDef_type->max_para_num,sizeof(char *));
	*cmd->parameters = (char *) calloc(MAX_PROMPT_LENGTH + MAX_PAPA_NUM,sizeof(char));

	// configure the number of parameter
	cmd->para_num = 1;
	
	// eliminate the command text
	Semantic_Segmentation(&token_buffer,&string_buffer," ",false);
	free(token_buffer); token_buffer = NULL;

	if(string_buffer){ // if there is any parameter after the command text of "echo"

		if(strcmp(string_buffer,"echo") == 0){
			// cmd->parameters[0] = "";
			printf("\n");

			return cmd;
		}

		// clear the char of \' and \" surrounding the string
		switch(*string_buffer){
			case '\'': 
			case '\"':
				if(strlen(string_buffer) <= 2){
					Print_errorInfo("Illegal manners occured in the parameters of \"echo\"",__FILE__,__LINE__);
					free(string_buffer); string_buffer = NULL;
					return cmd;
				}
				if((strstr(string_buffer+1,"\"") != NULL) || (strstr(string_buffer+1,"\'") != NULL)){
					strncpy(string_buffer, string_buffer + 1, strlen(string_buffer) -2);
					break;
				}else{
					Print_errorInfo("Illegal manners occured in the parameters of \"echo\"",__FILE__,__LINE__);
					free(string_buffer); string_buffer = NULL;
					return cmd;
				}

			default:
				 break;
		}

		// replace the $<env> with the value of the environmental variable
		while(string_buffer){ // while there is any string left
			token_buffer = (char *) calloc(MAX_PROMPT_LENGTH,sizeof(char));

			if(*string_buffer == '$'){ // if the first char of the string is '$'
				notUppercase_signal = (char *) calloc(2,sizeof(char));
				for(int i = 1; i < (int)strlen(string_buffer); i++){
					if(!((string_buffer[i] >= 'A') && (string_buffer[i] <= 'Z'))){ // record the first non-uppercase char
						
						strncpy(notUppercase_signal, string_buffer+i,1);
						break;
					}
				}

				if(*notUppercase_signal){ // if there is any non-uppercase char after '$'
					
					Semantic_Segmentation(&token_buffer,&string_buffer,notUppercase_signal,false);
					
					if((envValue = getenv(token_buffer+1)) == NULL){
						char * error_str = (char *) calloc(MAX_PROMPT_LENGTH,sizeof(char));
						sprintf(error_str,"The environment variable  %s  is not defined",token_buffer);
						Print_errorInfo(error_str,__FILE__,__LINE__);
						
						free(notUppercase_signal); notUppercase_signal = NULL;
						free(error_str); error_str = NULL;
						free(token_buffer); token_buffer = NULL; 
						continue;
					}
					strcat(cmd->parameters[0], envValue); 
					if(strcmp(notUppercase_signal," ") == 0){
						strcat(cmd->parameters[0]," ");
					}
				}else{
					if((envValue = getenv(string_buffer+1)) == NULL){
						char * error_str = (char *) calloc(MAX_PROMPT_LENGTH,sizeof(char));
						sprintf(error_str,"The environment variable %s is not defined",token_buffer);
						Print_errorInfo(error_str,__FILE__,__LINE__);
						free(error_str); error_str = NULL;
					}else{
						strcat(cmd->parameters[0], envValue);
						// strncpy(cmd->parameters[0], envValue, strlen(envValue)+1);	
					}
					string_buffer = NULL; // ending condition
				}
				free(notUppercase_signal); notUppercase_signal = NULL;
				
			}else{
				Semantic_Segmentation(&token_buffer,&string_buffer,"$",false);
				
				if(strcmp(token_buffer,"") == 0){
					strcat(cmd->parameters[0], string_buffer);
					free(token_buffer); token_buffer = NULL;
					break;
				}else{
					strcat(cmd->parameters[0], token_buffer); strcat(cmd->parameters[0], " ");
				}
			}
			free(token_buffer); token_buffer = NULL; 
		}
	}else{
		cmd->parameters[0] = "";
		printf("\n");
		free(string_buffer); string_buffer = NULL; 
		return cmd;
	}

	char * tmp_ptr = (char *) realloc((char *)cmd->parameters[0],(strlen(cmd->parameters[0])+1)*sizeof(char));
	if(tmp_ptr == NULL){
		Print_errorInfo("fail to allocate the memory space of the parameters of \"echo\"\n",__FILE__,__LINE__);
		return cmd;
	}
	cmd->parameters[0] = tmp_ptr;
	printf("%s\n", cmd->parameters[0]);

	return cmd;

	free(token_buffer); free(string_buffer); free(notUppercase_signal);
}

PARSER * _CD(PARSER * cmd){
	/**
	 * @brief	Change the work path of the current process to the path specified by "workpath"
	 */

	char * token_buffer = (char *) calloc(MAX_PROMPT_LENGTH,sizeof(char));
	char * string_buffer = cmd->cmd_string;
	char * workpath = (char *) calloc(MAX_ENV_VALUE_LENGTH,sizeof(char));

	// cd command configuration
	cmd->para_num = 1; 
	cmd->parameters = (char **) calloc(cmd->para_num,sizeof(char *));
	* cmd->parameters = (char *) calloc(MAX_PROMPT_LENGTH,sizeof(char));

	Semantic_Segmentation(&token_buffer,&string_buffer," ",false);
	
	if(strcmp(token_buffer,"") == 0){ // if there is no parameter after the command text of "cd"
		if((workpath = getenv("HOME")) == NULL){
			Print_errorInfo("HOME environment variable is not defined.\n",__FILE__,__LINE__);
		}else{
			if(chdir("/") != 0) Print_errorInfo("fail to change the work path of \"/\".\n",__FILE__,__LINE__);
		}
		
	}else{
		// decode the <env name> 
		if(*string_buffer == '$'){
			char *env_value = getenv(string_buffer+1);
			if(env_value == NULL){
				char * error_str = (char *) calloc(MAX_PROMPT_LENGTH,sizeof(char));
				sprintf(error_str,"The environment variable %s is not defined",token_buffer);
				Print_errorInfo(error_str,__FILE__,__LINE__);
				free(error_str); error_str = NULL;
			}else{
				strncpy(workpath,env_value,strlen(env_value)+1);
			}

		}else{
			strncpy(workpath,string_buffer,strlen(string_buffer));
		}

		if(access(workpath,F_OK) == 0){ // if the path is valid
			if(chdir(workpath) != 0){
				Print_errorInfo("fail to change the work path.\n",__FILE__,__LINE__);
			}else{
				strncpy(cmd->parameters[0], workpath, strlen(workpath)+1);
			}
		}else{
			Print_errorInfo("no such directory.\n",__FILE__,__LINE__);

		}
	}

	free(token_buffer); token_buffer = NULL;
	free(workpath);workpath = NULL;

	return cmd;
}